#include "vtime.h"
#include <sstream>
#include <iomanip> 
#include <thread> 
//#include <iostream> 

vbase::vtime::vtime()
{

}

vbase::vtime::~vtime()
{

}

std::shared_ptr<std::ostringstream> vbase::vtime::get_oss()
{
    static auto sp_oss = std::make_shared<std::ostringstream>();
    if(sp_oss.use_count()>0)
    {
        return sp_oss;
    }
    else
    {
        //if execute to this line, it's meaning static variable 
        //has already bee released when program exit.
        return std::make_shared<std::ostringstream>();
    }
}

std::string vbase::vtime::now()
{
    using namespace std::chrono;
    system_clock::time_point now = system_clock::now();
    std::time_t last = system_clock::to_time_t(now);

    auto ms = now.time_since_epoch();
    //std::chrono::nanoseconds
    //auto mills = duration_cast<std::chrono::nanoseconds>(ms).count()%(1000*1000*1000);
    auto mills = duration_cast<std::chrono::milliseconds>(ms).count()%(1000);

    auto sp_oss = get_oss();
    sp_oss->clear();
    sp_oss->str("");
    //_oss<<std::put_time(std::localtime(&last), "%F %T.") //windows can not work 
    *sp_oss<<std::put_time(std::localtime(&last), "%Y-%m-%d %H:%M:%S.")
        <<std::setfill('0')
        <<std::setw(3)<<mills;

    return sp_oss->str();
}

std::string vbase::vtime::now_fmt1()
{
    std::string now_str = now();
    now_str.pop_back();
    now_str.pop_back();
    now_str.pop_back();
    now_str.pop_back();

    return now_str;
}

std::string vbase::vtime::from_time_t(time_t time_sec)
{
    std::time_t last = time_sec;

    auto sp_oss = get_oss();
    sp_oss->clear();
    sp_oss->str("");
    //_oss<<std::put_time(std::localtime(&last), "%F %T.") //windows can not work 
    *sp_oss<<std::put_time(std::localtime(&last), "%Y-%m-%d %H:%M:%S");

    return sp_oss->str();
}

//format must be: 2020-11-24 15:15:22
time_t vbase::vtime::to_time_t(const std::string & time_str)
{
    time_t time1 = 0;
    std::istringstream iss{time_str};
    std::tm tm{0};

    if (!(iss >> std::get_time(&tm, "%Y-%m-%d %H:%M:%S")))
    {
        throw std::invalid_argument("get_time");
    }

    time1 = std::mktime(&tm);

    //tm1.tm_year -= 1900;
    //tm1.tm_mon -= 1;

    //time1 = mktime(&tm1);
    return time1;
}


void vbase::vtime::msleep(int time_ms)
{
    //struct timeval _delay;
    //_delay.tv_sec =time_ms/1000;
    //_delay.tv_usec =time_ms%1000 * 1000; 
    //select(0, NULL,NULL, NULL, &_delay);
    std::this_thread::sleep_for(std::chrono::milliseconds(time_ms));
}

void vbase::vtime::ssleep(int time_s)
{
    //struct timeval _delay;
    //_delay.tv_sec =time_s;
    //_delay.tv_usec =0; 
    //select(0, NULL,NULL, NULL, &_delay);
    std::this_thread::sleep_for(std::chrono::seconds(time_s));
}

void vbase::vtime::usleep(int time_us)
{
    std::this_thread::sleep_for(std::chrono::microseconds(time_us));
}

std::chrono::system_clock::duration::rep vbase::vtime::get_time()
{
    return std::chrono::system_clock::now().time_since_epoch().count();
}
